import 'dart:ui' as ui;
import 'dart:typed_data';

class DitherImageUtil {
  static final List<ui.Color> colorList = [
    ui.Color.fromARGB(255, 255, 255, 255), // White
    ui.Color.fromARGB(255, 0, 0, 0),       // Black
    ui.Color.fromARGB(255, 255, 0, 0),     // Red
    ui.Color.fromARGB(255, 255, 255, 0),   // Yellow
    ui.Color.fromARGB(255, 0, 255, 0),     // Green
    ui.Color.fromARGB(255, 0, 0, 255),     // Blue
  ];

  /// 直接处理 RGBA8888 格式的 Uint8List，并返回新的 Uint8List（也是 RGBA8888）
  static Uint8List rgbTripleDitherBytes(Uint8List rgba, int width, int height) {
    final Uint8List result = Uint8List.fromList(rgba);

    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        final int idx = (y * width + x) * 4;
        final int r = result[idx];
        final int g = result[idx + 1];
        final int b = result[idx + 2];

        final int nearestIdx = _findNearestColor(r, g, b);
        final ui.Color nearest = colorList[nearestIdx];

        final int rErr = r - nearest.red;
        final int gErr = g - nearest.green;
        final int bErr = b - nearest.blue;

        result[idx] = nearest.red;
        result[idx + 1] = nearest.green;
        result[idx + 2] = nearest.blue;

        _distributeError(result, width, height, x, y, rErr, gErr, bErr);
      }
    }

    return result;
  }

  static void _distributeError(Uint8List pixels, int width, int height, int x, int y, int rErr, int gErr, int bErr) {
    void applyError(int x, int y, double factor) {
      if (x < 0 || x >= width || y < 0 || y >= height) return;
      int i = (y * width + x) * 4;
      pixels[i] = _plusTruncateUchar(pixels[i], (rErr * factor).round());
      pixels[i + 1] = _plusTruncateUchar(pixels[i + 1], (gErr * factor).round());
      pixels[i + 2] = _plusTruncateUchar(pixels[i + 2], (bErr * factor).round());
    }

    applyError(x + 1, y, 7 / 16);
    applyError(x - 1, y + 1, 3 / 16);
    applyError(x, y + 1, 5 / 16);
    applyError(x + 1, y + 1, 1 / 16);
  }

  static int _findNearestColor(int r, int g, int b) {
    int bestIndex = 0;
    int minDistance = 1 << 30;
    for (int i = 0; i < colorList.length; i++) {
      final c = colorList[i];
      final int dr = r - c.red;
      final int dg = g - c.green;
      final int db = b - c.blue;
      final int dist = dr * dr + dg * dg + db * db;
      if (dist < minDistance) {
        minDistance = dist;
        bestIndex = i;
      }
    }
    return bestIndex;
  }

  static int _plusTruncateUchar(int a, int b) {
    final int result = a + b;
    return result.clamp(0, 255);
  }
}
